"""
https://git.oschina.net/caojun1989/vtags
"""
#===============================================================================
# BSD 2-Clause License

# Copyright (c) 2016, CaoJun
# All rights reserved.

# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:

# * Redistributions of source code must retain the above copyright notice, this
#   list of conditions and the following disclaimer.

# * Redistributions in binary form must reproduce the above copyright notice,
#   this list of conditions and the following disclaimer in the documentation
#   and/or other materials provided with the distribution.

# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#===============================================================================
__version__ = "2.0"
__project_url__ = "https://git.oschina.net/caojun1989/vtags"

import os
import sys
import re
import pickle

#-------------------------------------------------------------------------------
#print help
#-------------------------------------------------------------------------------
help = ''
try:
    help = sys.argv[1]
except:
    pass
if help in ['-h','-help']:
    print("(1) generate vtags at code dir, use command \"vtags\" ;"                                     )
    print("(2) config vtags vim at vtags gen dir \"/vtags.db/vim_local_config.py\","                    )
    print("    config items and detail look vim_local_config.py notes;"                                 )
    print("(3) support action in vim window:"                                                           )
    print("        1)  gi             : if cursor on module call, go in submodule;"                     )
    print("        2)  gu             : if cur module called before, go upper module;"                  )
    print("        3)  <Space><Left>  : trace cursor word signal source;"                               )
    print("        4)  <Space><Right> : trace cursor word signal dest;"                                 )
    print("        5)  <Space><Down>  : roll back;"                                                     )
    print("        6)  <Space><Up>    : go forward;"                                                    )
    print("        7)  <Space>v       : show current module topo "                                      )
    print("                             or fold/unfold sidebar items;"                                  )
    print("        8)  <Space>c       : add current cursor as checkpoint, can go back directly;"        )
    print("        9)  <Space>b       : add current cursor module as basemodule, not show in topo;"     )
    print("        10) <Space>        : in sidebar or report win, just go cursor line link;"            )
    print("        11) <Space>h       : hold cursor win, will not auto close it;"                       )
    print("        12) <Space>d       : in sidebar, delete valid items(base_module, checkpoint...);"    )
    print("        13) <Space>s       : save current vim snapshort,"                                    )
    print("                             use \"gvim/vim\" without input file to reload snapshort;"       )
    print("(4) -func to cll offline function !"                                                         )
    exit()

#-------------------------------------------------------------------------------
# get the install folder path
#-------------------------------------------------------------------------------
# when vtags.py run, this function can return the dir path vtags.py exist.
def cur_file_dir():
     path = sys.path[0]
     if os.path.isdir(path):
         return path
     elif os.path.isfile(path):
         return os.path.dirname(path)

# get the vtags.py's dir path, which is the install src path.
vtags_install_path = cur_file_dir()

#-------------------------------------------------------------------------------
# Offline function
#-------------------------------------------------------------------------------
offline_function_parms = None
try:
    if sys.argv[1] == '-func':
        offline_function_parms = sys.argv[2:]
except:
    pass
if offline_function_parms != None:
    sys.path.insert(0,vtags_install_path)
    import OfflineLib.OfflineFuncLib as OfflineFuncLib
    OfflineFuncLib.function_run(offline_function_parms)
    exit()


#-------------------------------------------------------------------------------
# when run vtags.py, create a folder named vtag.db at current dir
# and also rm the old vtags_db.log if exist.
#-------------------------------------------------------------------------------
vtags_db_folder_path = os.getcwd() + '/vtags.db'
os.system('mkdir -p %s'%(vtags_db_folder_path))
if os.path.isfile(vtags_db_folder_path + '/vtags_db.log'):
    os.system('rm -rf '+vtags_db_folder_path+'/vtags_db.log')

#-------------------------------------------------------------------------------
# import lib used in generate vtags.db
#-------------------------------------------------------------------------------
# add install dir path to python search path, to import all the needed python module
sys.path.insert(0,vtags_install_path)
# import the module used to generate vtags.db database
import Lib.GLB as GLB
G = GLB.G
GLB.vtags_db_log_path[0] = vtags_db_folder_path + '/vtags_db.log'
from Lib.BaseLib import *
import Lib.FileInfLib as FileInfLib

#-------------------------------------------------------------------------------
# get all the verilog file code inf
#-------------------------------------------------------------------------------
file_list = ''

# generate vtags.db current not support filelist
if len(sys.argv[1:]) != 0:
    print('Error: unknown parameters ! %s '%(sys.argv[1:].__str__()))
    exit()

# get all verilog files path from file_list
design_file_path_set      = FileInfLib.get_all_design_file_path_from_filelist(file_list)

# get all code inf
file_path_to_code_inf_dic = FileInfLib.init_get_file_path_to_code_inf_dic(design_file_path_set)


#-------------------------------------------------------------------------------
# add more inf to module_inf, subcall_inf, macro_inf
#-------------------------------------------------------------------------------
module_name_to_file_path_list_dic = {}
file_path_to_last_modify_time_dic = {}
for f in file_path_to_code_inf_dic:
    file_path_to_last_modify_time_dic[f] = file_path_to_code_inf_dic[f]['last_modify_time']
    module_inf_list = file_path_to_code_inf_dic[f]['module_inf_list'  ]
    for module_inf in module_inf_list:
        # module_inf['file_path']        = f
        # module_inf['last_modify_time'] = file_path_to_code_inf_dic[f]['last_modify_time']
        module_name_to_file_path_list_dic.setdefault(module_inf['module_name'],[])
        module_name_to_file_path_list_dic[ module_inf['module_name'] ].append(f)

# for f in file_path_to_code_inf_dic:
#     subcall_inf_list  = file_path_to_code_inf_dic[f]['subcall_inf_list' ]
#     for subcall_inf in subcall_inf_list:
#         subcall_inf['file_path']       = f

macro_name_to_macro_inf_list_dic = {}
for f in file_path_to_code_inf_dic:
    macro_inf_list = file_path_to_code_inf_dic[f]['macro_inf_list']
    for macro_inf in macro_inf_list:
        # macro_inf['file_path'] = f
        # macro_inf['last_modify_time'] = file_path_to_code_inf_dic[f]['last_modify_time']
        macro_name_to_macro_inf_list_dic.setdefault(macro_inf['macro_name'],[])
        macro_name_to_macro_inf_list_dic[macro_inf['macro_name']].append(macro_inf)

#-------------------------------------------------------------------------------
# set base module
#-------------------------------------------------------------------------------
all_basemodule_name_set_pkl_path = vtags_db_folder_path+'/pickle/all_basemodule_name_set.pkl'
all_basemodule_name_set = set()
if not os.path.isfile(all_basemodule_name_set_pkl_path):
    base_threshold          = G['BaseModuleInf']['BaseModuleThreshold']
    # first get all module instance number, if instance number bigger than base_threshold
    # tread corresponding module as base module
    module_name_to_instance_num_dic  = {}
    for f in file_path_to_code_inf_dic:
        subcall_inf_list = file_path_to_code_inf_dic[f]['subcall_inf_list']
        for subcall in subcall_inf_list:
            submodule_name = subcall['submodule_name']
            module_name_to_instance_num_dic.setdefault(submodule_name,0)
            module_name_to_instance_num_dic[submodule_name] += 1
    # check if beyond the base_threshold
    for module_name in module_name_to_instance_num_dic:
        if module_name_to_instance_num_dic[module_name] >= base_threshold:
            all_basemodule_name_set.add(module_name)

#-------------------------------------------------------------------------------
# pickle
#-------------------------------------------------------------------------------
os.system('mkdir -p %s'%(vtags_db_folder_path+'/pickle'))
# 1 pickle file_list,file_path_to_last_modify_time_dic or refresh vtags.db
if not file_list:
    file_list   = vtags_db_folder_path + '/design.filelist'
    file_list_p = open(file_list,'w')
    file_list_p.write(os.getcwd()+'\n')
    file_list_p.close()
vtags_db_refresh_inf = {
     'file_list'                         : file_list
    ,'file_path_to_last_modify_time_dic' : file_path_to_last_modify_time_dic
}
vtags_db_refresh_inf_pkl_path = vtags_db_folder_path+'/pickle/vtags_db_refresh_inf.pkl'
pickle_save(vtags_db_refresh_inf, vtags_db_refresh_inf_pkl_path)
# 2 pickle module_name_to_file_path_list_dic, for refresh single file subcall_inf
module_name_to_file_path_list_dic_pkl_path = vtags_db_folder_path+'/pickle/module_name_to_file_path_list_dic.pkl'
pickle_save(module_name_to_file_path_list_dic, module_name_to_file_path_list_dic_pkl_path)
# 3 pick all macro inf
macro_name_to_macro_inf_list_dic_pkl_path = vtags_db_folder_path+'/pickle/macro_name_to_macro_inf_list_dic.pkl'
pickle_save(macro_name_to_macro_inf_list_dic, macro_name_to_macro_inf_list_dic_pkl_path)
# 4 pick file_path_to_code_inf_dic
# pick save all f inf
for f in file_path_to_code_inf_dic:
    code_inf = file_path_to_code_inf_dic[f]
    del code_inf['macro_inf_list']
    code_inf_pkl_path = vtags_db_folder_path+'/pickle/design__%s.pkl'%(f.replace('/','__'))
    pickle_save(code_inf, code_inf_pkl_path)
# 5 used pickle save base module inf
if not os.path.isfile(all_basemodule_name_set_pkl_path):
    pickle_save(all_basemodule_name_set, all_basemodule_name_set_pkl_path)


#-------------------------------------------------------------------------------
# copy glable config to vtags.db to generate local config if no local config
#-------------------------------------------------------------------------------
if not os.path.isfile(vtags_db_folder_path + '/vim_local_config.py'):
    os.system('cp %s/vim_glb_config.py %s/vim_local_config.py'%(vtags_install_path, vtags_db_folder_path))
